package com.cruise.oauth.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cruise.common.core.constant.AuthConstants;
import com.cruise.common.web.ex.BizException;
import com.cruise.common.web.result.Result;
import com.cruise.common.web.result.ResultCode;
import com.cruise.common.web.util.WebUtils;
import com.cruise.oauth.bean.User;
import com.cruise.oauth.enums.UserStatusEnum;
import com.cruise.system.userapi.dto.RegistUserDTO;
import com.cruise.system.userapi.entity.SysRole;
import com.cruise.system.userapi.entity.SysUser;
import com.cruise.system.userapi.feignapi.FeignSystemApi;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.cruise.common.core.constant.AuthConstants.VERIFICATION_CODE;


/**
 * 自定义用户认证和授权
 * @author crusie
 */
@Service
@AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {

    static Logger logger= LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private FeignSystemApi feignSystemApi;

    private RedisTemplate redisTemplate;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public User loadUserByUsername(String username) throws UsernameNotFoundException {


        boolean isRegist = false;
        String clientId = WebUtils.getHttpServletRequest().getParameter(AuthConstants.JWT_CLIENT_ID_KEY);
//        User user = null;
        // 可用性 :true:可用 false:不可用  后期从数据库中获取
        boolean enabled = true;
        // 过期性 :true:没过期 false:过期  后期从数据库中获取
        boolean accountNonExpired = true;
        // 有效性 :true:凭证有效 false:凭证无效  后期从数据库中获取
        boolean credentialsNonExpired = true;
        // 锁定性 :true:未锁定 false:已锁定 后期从数据库中获取
        boolean accountNonLocked = true;
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
        SysUser sysUser = new SysUser();

        switch (clientId) {
            // 后台用户
            case AuthConstants.ADMIN_CLIENT_ID:
                break;
            // 小程序会员
            case AuthConstants.WEAPP_CLIENT_ID:
                break;
            // H5 端 登陆, 手机号 + 验证码登陆，此时的username 为 手机号,如果是新用户，直接注册
            case AuthConstants.H5_CLIENT_ID:
                //从数据库中通过手机号查询获取该账户信息，
                Result<SysUser> result = feignSystemApi.findByPhone(username);
                sysUser = result.getData();
                if (ObjectUtil.isNull(sysUser)) {
                    sysUser = new SysUser();
                    // 如果手机号不存在，则通过手机号注册一个账号，
                    RegistUserDTO userDTO = new RegistUserDTO(username);
                    Result<String> registRes = feignSystemApi.regist(userDTO);
                    if(Result.success().getCode().equals(registRes.getCode())){
                        //用户注册成功
                        sysUser.setId(registRes.getData());
                    }else{
                        logger.error("手机号：{},注册新用户失败", username);
                        throw new RuntimeException("注册新用户失败");
                    }
                    // 从 redis 中 通过手机号 获取 验证码
                    Object o = redisTemplate.opsForValue().get(VERIFICATION_CODE + username.trim());
                    if(ObjectUtil.isNull(o)){
                        logger.warn("手机号：{} 验证码无效",username);
                        throw new UsernameNotFoundException("验证码无效");
                    }
                    sysUser.setPassword(passwordEncoder.encode(o.toString()));
                    sysUser.setUsername(username);
                    System.out.println(sysUser.toString());
                    isRegist = true;
                    break;
                }
                Object o = redisTemplate.opsForValue().get(VERIFICATION_CODE + username.trim());
                if(ObjectUtil.isNull(o)){
                    logger.warn("手机号：{} 验证码过期",username);
                    throw new UsernameNotFoundException("验证码过期");
                }
                //系统会自动 用输入的 password 参数与 sysUser 中的password 比较
                sysUser.setPassword(passwordEncoder.encode(o.toString()));
                sysUser.setUsername(username);
                System.out.println(sysUser.toString());
                break;
            default:

        }
        if(!isRegist){
            // 新注册用户不用校验
            if (sysUser.getStatus() == UserStatusEnum.AccountExceptionStatus.DISABLED.getCode()) {
                throw new BizException(ResultCode.USER_ACCOUNT_DISABLED);
            } else if (sysUser.getStatus() == UserStatusEnum.AccountExceptionStatus.LOCKED.getCode()) {
                throw new BizException(ResultCode.USER_ACCOUNT_LOCKED);
            } else if (sysUser.getStatus() == UserStatusEnum.AccountExceptionStatus.EXPIRED.getCode()) {
                throw new BizException(ResultCode.USER_ACCOUNT_EXPIRED);
            }
        }

        //获取用户角色列表
        Result<List<SysRole>> result1 = this.feignSystemApi.getRoleByUserId(sysUser.getId());
        List<SysRole> roles = result1.getData();
        if (!CollUtil.isEmpty(roles)){
            for (SysRole role:roles){
                //角色
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getId().toString());
                grantedAuthorities.add(grantedAuthority);
            }
        }
        //封装返回
        return new User(sysUser.getId(),sysUser.getUsername(),sysUser.getPassword(),
                enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
    }

}
